package tabuleiro
	
import (. "fmt"; . "./pecaPkg"; . "./util")
	
	const( MAX_MOVIMENTOS int = 50)
	var prompt string = ">>> "
	type Tabuleiro struct {matriz [8] [8] *Peca}
	
	func (tabuleiro *Tabuleiro) SetPecaDama (x int, y int){
			tabuleiro.matriz[x][y].SetDama(true)
	}
	
	func (tabuleiro *Tabuleiro) GetPecas (cor int) ([12] *Tupla){
		var pecas [12] *Tupla
		contador := 0
		for i:=0; i<=7; i++{
			for j:=0; j<=7; j++{
				if (tabuleiro.matriz[i][j]!=nil && tabuleiro.matriz[i][j].GetCor() == cor){
					newTupla := new(Tupla)
					newTupla.X = i
					newTupla.Y = j
					pecas[contador] = newTupla
					contador++
				}
			}
		}
		return pecas
	} 
	

	func (tabuleiro *Tabuleiro) IsTravou (cor int) bool{
		for i:=0; i<7; i++{
			for j:=0; j<7; j++{
				if (tabuleiro.matriz[i][j]!=nil && !tabuleiro.matriz[i][j].EhDama()){
					if (tabuleiro.PodeMover(i, j, i - 1, j + 1, cor) || tabuleiro.PodeMover(i, j, i - 1, j - 1, cor) ||
						tabuleiro.PodeMover(i, j, i + 1, j + 1, cor) || tabuleiro.PodeMover(i, j, i + 1, j - 1, cor)){
							return false
					}
				}
			
			}
		}
		return true
	
	}
	
	func (tabuleiro *Tabuleiro) IsZerou (cor int) bool{
		for i:=0; i<=7; i++{
			for j:=0; j<=7; j++{
				if (tabuleiro.matriz[i][j]!=nil){
					if (tabuleiro.matriz[i][j].GetCor() == cor)	{
						return false
					}		
				}
			}
		}
		return true
	}
	func (tabuleiro *Tabuleiro) GetMovimentos (cor int) [MAX_MOVIMENTOS] *Tupla {
		
		contador := 0
		pecas := tabuleiro.GetPecas(cor)
		var movimentos [MAX_MOVIMENTOS] *Tupla
		var mudancaX1 int
		var mudancaY1 int
		var mudancaX2 int
		var mudancaY2 int			
					
		//Valores para somar
		if(cor == Preto){
			mudancaX1 = 1
			mudancaY1 = -1
			mudancaX2 = 1
			mudancaY2 = 1
		}else{
			mudancaX1 = -1
			mudancaY1 = -1
			mudancaX2 = -1
			mudancaY2 = 1
		}
		
		for i:=0; i < 12 && pecas[i] != nil; i++{
		
			if (!tabuleiro.matriz[pecas[i].X][pecas[i].Y].EhDama()) {
			
				if (tabuleiro.PodeMover(pecas[i].X, pecas[i].Y, pecas[i].X + mudancaX1, pecas[i].Y + mudancaY1, cor)){
					 newTupla := new(Tupla)
					 newTupla.X = pecas[i].X
					 newTupla.Y = pecas[i].Y
					 newTupla.FicarX = pecas[i].X + mudancaX1
					 newTupla.FicarY = pecas[i].Y + mudancaY1
				 	 movimentos[contador] = newTupla
				 	 contador++
				}
				if(tabuleiro.PodeMover(pecas[i].X, pecas[i].Y, pecas[i].X + mudancaX2, pecas[i].Y + mudancaY2, cor)){
					 newTupla := new(Tupla)
					 newTupla.X = pecas[i].X
					 newTupla.Y = pecas[i].Y
					 newTupla.FicarX = pecas[i].X + mudancaX2
					 newTupla.FicarY = pecas[i].Y + mudancaY2
					 movimentos[contador] = newTupla
				 	 contador++
				}
			}else{
				for x:=-1; x<=1; x++{
					if (x == 0){
						continue
					}
					for y:=-1; y<=1; y++{
						if (y==0){
							continue
						}
						
						if (tabuleiro.PodeMover(pecas[i].X, pecas[i].Y, pecas[i].X + x, pecas[i].Y + y, cor)){
							 newTupla := new(Tupla)
							 newTupla.X = pecas[i].X
							 newTupla.Y = pecas[i].Y
							 newTupla.FicarX = pecas[i].X + x
					 		 newTupla.FicarY = pecas[i].Y + y
					 		 movimentos[contador] = newTupla
				 	 		 contador++	
						}
					}
				}
			}
		}
		
		return movimentos
	}
	
	func (tabuleiro *Tabuleiro) PodeMoverDama (posX int, posY int, novoPosX int, novoPosY int, cor int) (bool){
				
				auxX := posX
				auxY := posY
				
				if (novoPosX - posX > 0 && novoPosY - posY > 0){
					for i:=posX; i<novoPosX; i++ {
						if (tabuleiro.matriz[posX + 1][posY + 1] != nil){
							return false
						}
						auxX+= 1;
						auxY+= 1;
					}
			
				} else if (novoPosX - posX < 0 && novoPosY - posY < 0){
					for i:=posX; i>novoPosX; i-- {
						if (tabuleiro.matriz[posX - 1][posY - 1] != nil){
							return false
						}
						auxX-= 1;
						auxY-= 1;
					}
					
				} else if (novoPosX - posX < 0 && novoPosY - posY > 0){
					for i:=posX; i>novoPosX; i-- {
						if (tabuleiro.matriz[posX - 1][posY + 1] != nil){
							return false
						}
						auxX-= 1;
						auxY+= 1;
					}
				}else{
					for i:=posX; i<novoPosX; i++ {
						if (tabuleiro.matriz[posX + 1][posY - 1] != nil){
							return false
						}
						auxX+= 1;
						auxY-= 1;
					}
				}
				
				if (auxX != novoPosX || auxY != novoPosY){
						return false
				}
				
				return true			
	}

	
	func (tabuleiro *Tabuleiro) PodeMover (posX int, posY int, novoPosX int, novoPosY int, cor int) (bool){
		
			if (posX > 7 || posY > 7 || posX < 0 || posY < 0){
				return false
			}
			if (novoPosX < 0 || novoPosY < 0 || novoPosX > 7 || novoPosY > 7){
				return false
			}
			if (tabuleiro.matriz[novoPosX][novoPosY]!=nil || tabuleiro.matriz[posX][posY]==nil){
				return false
			}
			if (tabuleiro.matriz[posX][posY].GetCor() != cor){
				return false
			}
			if (!tabuleiro.matriz[posX][posY].EhDama()){
					return ((((novoPosY == posY + 1 && novoPosX == posX + 1) || (novoPosY == posY - 1 && novoPosX == posX + 1)) && tabuleiro.matriz[posX][posY].GetCor() == Preto)|| (((novoPosY == posY + 1 && novoPosX == posX - 1) ||  (novoPosY == posY - 1 && novoPosX == posX - 1)) && tabuleiro.matriz[posX][posY].GetCor() == Vermelho))
			}else {
				return tabuleiro.PodeMoverDama (posX, posY, novoPosX, novoPosY, cor)
			}	
			
			return false
	}
	
	func (tabuleiro *Tabuleiro) PodeMoverComida (posX int, posY int, novoPosX int, novoPosY int, cor int) (bool){
					
			if (posX > 7 || posY > 7 || posX < 0 || posY < 0){
				return false
			}
			if (novoPosX < 0 || novoPosY < 0 || novoPosX > 7 || novoPosY > 7){
				return false
			}
			if (tabuleiro.matriz[novoPosX][novoPosY]!=nil || tabuleiro.matriz[posX][posY]==nil){
				return false
			}
			if (tabuleiro.matriz[posX][posY].GetCor() != cor){
				return false
			}
			if (!tabuleiro.matriz[posX][posY].EhDama()){
					return ((novoPosY == posY + 1 && novoPosX == posX + 1) || (novoPosY == posY - 1 && novoPosX == posX + 1) || (novoPosY == posY + 1 && novoPosX == posX - 1) ||  (novoPosY == posY - 1 && novoPosX == posX - 1))
			}else {
				return tabuleiro.PodeMoverDama (posX, posY, novoPosX, novoPosY, cor)
			}	
			
			return false
	
	}
	
	func (tabuleiro *Tabuleiro) DeletarPeca (posX int, posY int){	
		tabuleiro.matriz[posX][posY] = nil
	
	}
	
	
	func (tabuleiroEntrada *Tabuleiro) GetOpcoesComida (posX int, posY int, cor int) (*[MAX_MOVIMENTOS] Tupla) {
		tabuleiro := tabuleiroEntrada.Copy()
		var caminhos [MAX_MOVIMENTOS] Tupla
		contador :=0
		
		if (tabuleiro.matriz[posX][posY].EhDama() == false){
		
		if (tabuleiro.PodeComer(posX, posY, posX + 1, posY + 1, posX + 2, posY + 2)){
				caminhos[contador].X = posX + 1
				caminhos[contador].Y = posY + 1
				caminhos[contador].FicarX = posX + 2
				caminhos[contador].FicarY = posY + 2
				caminhos[contador].Comer = true
				contador+=1;
		}
		if (tabuleiro.PodeComer(posX, posY, posX + 1, posY - 1, posX + 2, posY - 2)){
				caminhos[contador].X = posX + 1
				caminhos[contador].Y= posY - 1
				caminhos[contador].FicarX = posX + 2
				caminhos[contador].FicarY = posY - 2
				caminhos[contador].Comer = true
				contador+=1;
		}
		if (tabuleiro.PodeComer(posX, posY, posX - 1, posY + 1, posX - 2, posY + 2)){
				caminhos[contador].X = posX - 1 
				caminhos[contador].Y = posY + 1
				caminhos[contador].FicarX = posX - 2
				caminhos[contador].FicarY = posY + 2
				caminhos[contador].Comer = true
				contador+=1;
		}
		if (tabuleiro.PodeComer(posX, posY, posX - 1, posY - 1, posX - 2, posY - 2)){
				caminhos[contador].X = posX - 1
				caminhos[contador].Y = posY - 1
				caminhos[contador].FicarX = posX - 2
				caminhos[contador].FicarY = posY - 2
				caminhos[contador].Comer = true
				contador+=1;
		}
		
		}else{	
			for x:=-1; x<=1; x++{
				if (x == 0){
					continue
				}
				for y:=-1; y<=1; y++{
					if (y == 0){
						continue
					}
					tupla := tabuleiro.GetOpcaoDirecaoDama(posX, posY, x, y, cor)
					
					if (tupla.Comer){
						caminhos[contador] = *tupla
						contador+=1;
						incx, incy := descobreIncremento(tupla.X, tupla.Y, tupla.FicarX, tupla.FicarY)
						tabuleiro.ComerPeca (posX, posY, tupla, cor) 
						for ; tabuleiro.PodeMover(tupla.FicarX, tupla.FicarY, tupla.FicarX + incx, tupla.FicarY + incy, cor); {
							tabuleiro.ImprimeTabuleiro()
							tuplaAux:=new(Tupla)
							tuplaAux.X = posX
							tuplaAux.Y = posY
							tuplaAux.FicarX = tupla.FicarX + x 
							tuplaAux.FicarY = tupla.FicarY + y
							tuplaAux.Comer=true
							caminhos[contador] = *tuplaAux
							contador+=1;
							tupla=tuplaAux
						}	
					}
				}
			}
		}
		
		return &caminhos
	}
	
	func descobreIncremento (x int, y int, x1 int, y1 int) (incx int, incy int){
		if (x1 - x == -1){
			incx = -1
			if (y1 - y == -1){
				incy = -1
			}else if (y1 - y == 1) {
				incy = 1
			}
		}else if (x1 - x == 1){
			incx = 1
			if (y1 - y == -1){
				incy = -1
			}else if (y1 - y == 1) {
				incy = 1
			}
		}
		return incx, incy
	
	}
	
	func (tabuleiro *Tabuleiro) PodeComer (posX int, posY int, comerX int, comerY int, ficarX int, ficarY int)(bool){
		if (posX < 0 || posY < 0 || posX > 7 || posY > 7 || comerX < 0 || comerY < 0 || comerX > 7 || comerY > 7 || ficarX < 0|| ficarY < 0|| ficarX > 7|| ficarY > 7 ){
			return false
		}
		if (tabuleiro.matriz[posX][posY] == nil){
			return false
		}else{
			if (tabuleiro.matriz[comerX][comerY] == nil){
				return false
			}else if (tabuleiro.matriz[comerX][comerY] != nil){
		    	if (tabuleiro.matriz[posX][posY].GetCor() == tabuleiro.matriz[comerX][comerY].GetCor()){
					return false
				}	
			}else if (tabuleiro.matriz[ficarX][ficarY] != nil){
				return false
			}
		}
		if (tabuleiro.matriz[ficarX][ficarY] != nil){
				return false
		}
		return true
	
	}
	
	func (tabuleiro *Tabuleiro) MoverPeca (posX int, posY int, novoPosX int, novoPosY int, cor int, comida bool) (bool){
		if  !comida && tabuleiro.PodeMover (posX, posY, novoPosX, novoPosY, cor){ 	
			tabuleiro.matriz[novoPosX][novoPosY] = tabuleiro.matriz[posX][posY]
			tabuleiro.matriz[posX][posY] = nil
			return true
		}else if comida && tabuleiro.PodeMoverComida (posX, posY, novoPosX, novoPosY, cor){
			tabuleiro.matriz[novoPosX][novoPosY] = tabuleiro.matriz[posX][posY]
			tabuleiro.matriz[posX][posY] = nil
			return true
		}
		return false		
	}
	
	func (tabuleiro *Tabuleiro) ComerPeca (posAtualX int, posAtualY int, tupla *Tupla, cor int){
		tabuleiro.DeletarPeca (tupla.X, tupla.Y)
		tabuleiro.MoverPeca (posAtualX, posAtualY, tupla.X, tupla.Y, cor, true)
		tabuleiro.MoverPeca (tupla.X, tupla.Y, tupla.FicarX, tupla.FicarY, cor, true)
	}
	
	func (tabuleiro *Tabuleiro) GetOpcaoDirecaoDama(posX int, posY int, incX int, incY int, cor int) (*Tupla){
		auxX:=posX + incX
		auxY:=posY + incY
		tupla:= new (Tupla)
		
		for i:=0; i>=0; i++{
			if (tabuleiro.PodeMover(posX, posY, auxX, auxY, cor)){
				auxX+=incX
				auxY+=incY
			}else{
				break
			}
		}
		
		if (tabuleiro.PodeComer(posX, posY, auxX, auxY, auxX + incX, auxY + incY)){
			tupla.X = auxX
			tupla.Y = auxY
			tupla.FicarX = auxX + incX
			tupla.FicarY = auxY + incY
			tupla.Comer=true
		}
				
		return tupla
	}
	
	func  temOpcaoComida (tuplas [4]*Tupla) bool {
		for i:=0; i<4; i++{
			if (tuplas[i].Comer){
				return true;
			}
		}
		return false
	}
	
	func verificaOpcao (x int, y int, tuplas[4] *Tupla) (bool, *Tupla){
		for i:=0; i<4; i++{
			if (tuplas[i].X == x && tuplas[i].Y == y){
				return true, tuplas[i];
			}
		} 
		return false, nil
	}
	
	func (tabuleiro *Tabuleiro) PreencherTabuleiro () {
		
			for i := 0; i<3; i++ {
				if (i % 2 == 0){
					for j := 0; j<4; j++{
						peca := new (Peca)
						peca.SetCor(Preto)
						peca.SetDama(false)
						tabuleiro.matriz [i][(2*j)] = peca
					
					} 
					
				}else{
					for j := 0; j<4; j++{
						peca := new (Peca)
						peca.SetCor(Preto)
						peca.SetDama(false)
						tabuleiro.matriz [i][(2*j) + 1] = peca
					
					}
				}	
			
			}
			for i := 7; i>4; i-- {
				if (i % 2 == 0){
					for j := 0; j<4; j++{
						peca := new (Peca)
						peca.SetCor(Vermelho)
						peca.SetDama(false)
						tabuleiro.matriz [i][(2*j)] = peca
					
					} 
					
				}else{
					for j := 0; j<4; j++{
						peca := new (Peca)
						peca.SetCor(Vermelho)
						peca.SetDama(false)
						tabuleiro.matriz [i][(2*j) + 1] = peca
					
					}
				}	
			
			}
		
	}
	
	func (tabuleiro *Tabuleiro) NumDePecas (cor int) (num int) {
		for i:=0; i<8; i++ {
			for j:=0; j<8; j++{
				if (tabuleiro.matriz[i][j] == nil){
				
				}else{
					if (tabuleiro.matriz[i][j].GetCor() == cor){
						num+=1;
					}
				}	
			
			}
		}
		
		return num		
	
	}
	
	
	
	
	func mod (num int) (int){
		if (num < 0){
			return -num
		}
		return num
	}
	
	func (tabuleiro *Tabuleiro) Copy() *Tabuleiro {
		tabuleiroCopy := new(Tabuleiro)
		for i:=0; i < len(tabuleiro.matriz); i++ {
			for j:=0; j < len(tabuleiro.matriz[i]); j++ {
				if(tabuleiro.matriz[i][j] != nil){
					tabuleiroCopy.matriz[i][j] = tabuleiro.matriz[i][j].Copy()
				}
			}
		}
		return tabuleiroCopy
	}

func (tabuleiro *Tabuleiro) ViraDama(posX int, posY int, cor int) bool{
	if (tabuleiro.matriz[posX][posY] == nil){
		return false
	}else{
		if (cor == Vermelho){
			if (posX == 0){
				tabuleiro.matriz[posX][posY].SetDama(true)
				return true
			}else{
				return false
			}
		}else if (cor == Preto){
			if (posX == 7){
				tabuleiro.matriz[posX][posY].SetDama(true)
				return true
			}else{
				return false
			}
		}
	}
	return false
}
	
func (tabuleiro *Tabuleiro) ImprimeTabuleiro() {
	Println (prompt + "+++ Estado do tabuleiro atual +++")
	Println("")
	Print("    ")
	for i:= 7; i >= 0; i-- {
		Printf(" %d  ", i)
	}
	Println("")
	
	for i:= 0; i < 8 ; i++ {
		Printf("%d  | ", i)
		for j:= 7; j >= 0; j-- {
			if(tabuleiro.matriz[i][j] != nil){
				Print(tabuleiro.matriz[i][j].StringPeca())
			}else{
				Print(" ")
			}
			Print(" | ")
		}
		Println()
	}
	
	Println()
	Println("============================================")
	Println()
}

	
		